package com.gobo.jinghuimall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.gobo.common.constant.CartConstant;
import com.gobo.common.vo.SkuInfoEntity;
import com.gobo.jinghuimall.cart.entiry.to.UserInfoTo;
import com.gobo.jinghuimall.cart.entiry.vo.Cart;
import com.gobo.jinghuimall.cart.entiry.vo.CartItem;
import com.gobo.jinghuimall.cart.feign.ProductFeignService;
import com.gobo.jinghuimall.cart.interceptor.CartInterceptor;
import com.gobo.jinghuimall.cart.service.CartService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ProductFeignService productFeignService;

    @Autowired
    private ThreadPoolExecutor executor;

    /**
     * 获取购物车数据
     *
     * @return
     */
    @Override
    public Cart getCart() throws ExecutionException, InterruptedException {
        //通过线程获取
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        Cart cart = new Cart();
        BoundHashOperations<String, Object, Object> ops;
        if (userInfoTo.getUserId() != null) {
            // 登录了
            // 将未登录的合并
            ops = redisTemplate.boundHashOps(CartConstant.CART_PREFIX + userInfoTo.getUserKey());
            List<CartItem> cartItemsNoLogin = getCartItems(ops);
            if (cartItemsNoLogin != null && cartItemsNoLogin.size() > 0) {
                for (CartItem cartItem : cartItemsNoLogin) {
                    //添加至购物车
                    addToCart(cartItem.getSkuId(), cartItem.getCount());
                    //删除对应key值临时购物车中的对应skuId
                    ops.delete(cartItem.getSkuId().toString());
                }
            }
            //获取用户的
            ops = redisTemplate.boundHashOps(CartConstant.CART_PREFIX + userInfoTo.getUserId());
            List<CartItem> cartItemLogin = getCartItems(ops);
            cart.setItems(cartItemLogin);
        } else {
            // 未登录
            ops = redisTemplate.boundHashOps(CartConstant.CART_PREFIX + userInfoTo.getUserKey());
            List<CartItem> cartItems = getCartItems(ops);
            cart.setItems(cartItems);
        }
        return cart;
    }

    /**
     * 获取用户的购物车详情
     * @param ops
     * @return
     */
    private List<CartItem> getCartItems(BoundHashOperations<String, Object, Object> ops) {
        List<Object> values = ops.values();
        if (values != null && values.size() > 0) {
            List<CartItem> cartItems = values.stream().map(item -> {
                String s = (String) item;
                CartItem cartItem = JSON.parseObject(s, CartItem.class);
                return cartItem;
            }).collect(Collectors.toList());
            return cartItems;
        } else {
            return null;
        }
    }

    /**
     * 添加到购物车
     *
     * @param skuId
     * @param count
     * @return
     */
    @Override
    public CartItem addToCart(Long skuId, Integer count) throws ExecutionException, InterruptedException {
        //此时hash  key是用户ID  商品ID   商品属性
        BoundHashOperations<String, Object, Object> hashOps = getHashOps();
        CartItem cartItem;
        String s = (String) hashOps.get(skuId.toString());
        if (StringUtils.isEmpty(s)) {
            // 添加新商品
            cartItem = new CartItem();
            //通过异步编排，提高效率
            CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
                // 远程查询 skuInfo
                SkuInfoEntity skuInfoEntity = productFeignService.getSkuInfo(skuId);
                //设置对应的商品sku的详细属性
                cartItem.setPrice(skuInfoEntity.getPrice());
                cartItem.setTitle(skuInfoEntity.getSkuTitle());
                cartItem.setSkuId(skuId);
                cartItem.setChecked(true);
                cartItem.setCount(count);
                cartItem.setDefaultImg(skuInfoEntity.getSkuDefaultImg());
            }, executor);
            CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
                // 远程查询sku对应的属性
                List<String> saleAttr = productFeignService.getSaleAttr(skuId);
                cartItem.setAttrs(saleAttr);
            }, executor);
            // 放入reids
            CompletableFuture<Void> allof = CompletableFuture.allOf(future1, future2);
            //get会阻塞，但异步不会
            allof.get();
            String cartItemJson = JSON.toJSONString(cartItem);
            hashOps.put(skuId.toString(), cartItemJson);
        } else {
            //如果购物车中已经包含
            cartItem = JSON.parseObject(s, CartItem.class);
            //对数量进行+1操作
            cartItem.setCount(cartItem.getCount() + count);
            String cartItemJson = JSON.toJSONString(cartItem);
            //重新刷回缓存中
            hashOps.put(skuId.toString(), cartItemJson);
        }
        return cartItem;
    }

    @Override
    public CartItem getCartItem(Long skuId) {
        BoundHashOperations<String, Object, Object> hashOps = getHashOps();
        String s = (String) hashOps.get(skuId.toString());
        CartItem cartItem = JSON.parseObject(s, CartItem.class);
        return cartItem;
    }

    /**
     * 更改数量
     *
     * @param skuId
     * @param count
     */
    @Override
    public void countChange(Long skuId, Integer count) {
        BoundHashOperations<String, Object, Object> hashOps = getHashOps();
        CartItem cartItem = getCartItem(skuId);
        cartItem.setCount(count);
        System.out.println(cartItem);
        String s = JSON.toJSONString(cartItem);
        System.out.println(s);
        hashOps.put(skuId.toString(), s);
    }

    @Override
    public void checkItem(Long skuId, Boolean check) {
        BoundHashOperations<String, Object, Object> hashOps = getHashOps();
        CartItem cartItem = getCartItem(skuId);
        cartItem.setChecked(check);
        String s = JSON.toJSONString(cartItem);
        hashOps.put(skuId.toString(), s);
    }

    /**
     * 删除 cartItem
     *
     * @param skuId
     */
    @Override
    public void deleteItem(Long skuId) {
        BoundHashOperations<String, Object, Object> hashOps = getHashOps();
        hashOps.delete(skuId.toString());
    }

    @Override
    public List<CartItem> getCartByChecked() throws ExecutionException, InterruptedException {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        if (userInfoTo.getUserId() != null) {
            BoundHashOperations<String, Object, Object> ops = getHashOps();
            List<CartItem> cartItems = getCartItems(ops);
            if (cartItems != null && cartItems.size() > 0) {
                List<CartItem> collect = cartItems.stream().filter(CartItem::getChecked)
                        .map(item -> {
                            //  远程查最新价格
                            SkuInfoEntity skuInfo = productFeignService.getSkuInfo(item.getSkuId());
                            item.setPrice(skuInfo.getPrice());
                            return item;
                        }).collect(Collectors.toList());
                return collect;
            }
        }
        return null;
    }

    /**
     * hash (K - k v)
     * <p>
     * K --> userKey
     * k --> skuId
     * v --> cartItem
     * <p>
     * 绑定userKey的hash操作
     *
     * @return
     */
    private BoundHashOperations<String, Object, Object> getHashOps() {
        String userKey = "";
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        if (userInfoTo.getUserId() != null) {
            // 登录了
            userKey = CartConstant.CART_PREFIX + userInfoTo.getUserId();
        } else {
            // 未登录
            userKey = CartConstant.CART_PREFIX + userInfoTo.getUserKey();
        }
        BoundHashOperations<String, Object, Object> operation = redisTemplate.boundHashOps(userKey);
        return operation;
    }
}
